<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LangGraph 详细介绍与智能客服实现教程</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f5f7fa;
            padding-bottom: 50px;
            scroll-behavior: smooth;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        
        header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 80px 0 60px;
            text-align: center;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        h1 {
            font-size: 2.8rem;
            margin-bottom: 20px;
            font-weight: 700;
        }
        
        h2 {
            font-size: 2.2rem;
            margin: 40px 0 20px;
            color: #667eea;
            padding-bottom: 10px;
            border-bottom: 2px solid #eaeaea;
        }
        
        h3 {
            font-size: 1.6rem;
            margin: 30px 0 15px;
            color: #444;
        }
        
        h4 {
            font-size: 1.3rem;
            margin: 25px 0 10px;
            color: #555;
        }
        
        p {
            margin-bottom: 20px;
            font-size: 1.1rem;
            color: #555;
        }
        
        .subtitle {
            font-size: 1.3rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
        }
        
        .content {
            background: white;
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            padding: 40px;
            margin-top: -40px;
            position: relative;
            z-index: 1;
        }
        
        section {
            margin-bottom: 40px;
            scroll-margin-top: 30px;
        }
        
        .toc {
            background: #f8f9ff;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 25px;
            margin: 30px 0;
        }
        
        .toc h3 {
            margin-top: 0;
            color: #667eea;
        }
        
        .toc ul {
            list-style: none;
            padding-left: 20px;
        }
        
        .toc li {
            margin: 10px 0;
        }
        
        .toc a {
            color: #555;
            text-decoration: none;
            transition: color 0.3s;
        }
        
        .toc a:hover {
            color: #667eea;
        }
        
        pre {
            background-color: #f5f7fa;
            border-radius: 6px;
            padding: 15px;
            overflow-x: auto;
            margin: 15px 0;
            font-family: 'Courier New', Courier, monospace;
            border: 1px solid #eaeaea;
            position: relative;
        }
        
        .copy-btn {
            position: absolute;
            top: 10px;
            right: 10px;
            background-color: #667eea;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 5px 10px;
            font-size: 0.8em;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        
        .copy-btn:hover {
            background-color: #5a67d8;
        }
        
        .copy-btn.copied {
            background-color: #4caf50;
        }
        
        .flow-diagram-container {
            margin: 30px 0;
            text-align: center;
        }
        
        /* 流程图样式 */
        .flow-svg {
            width: 100%;
            max-width: 800px;
            height: auto;
            margin: 0 auto;
        }
        
        code {
            font-family: 'Courier New', Courier, monospace;
            background: #f6f8fa;
            padding: 2px 6px;
            border-radius: 3px;
            font-size: 0.9em;
        }
        
        pre code {
            background: none;
            padding: 0;
        }
        
        ul, ol {
            margin: 20px 0;
            padding-left: 30px;
        }
        
        li {
            margin: 8px 0;
        }
        
        .note {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .warning {
            background: #f8d7da;
            border-left: 4px solid #dc3545;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .success {
            background: #d4edda;
            border-left: 4px solid #28a745;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .feature-card {
            background: #f8f9ff;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 25px;
            margin: 20px 0;
            transition: transform 0.3s, box-shadow 0.3s;
        }
        
        .feature-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 30px rgba(0,0,0,0.12);
        }
        
        .code-tab {
            background: #f6f8fa;
            border: 1px solid #e1e4e8;
            border-radius: 6px;
            margin: 20px 0;
            overflow: hidden;
        }
        
        .code-tab-header {
            background-color: #f5f7fa;
            padding: 10px 15px;
            border-bottom: 1px solid #eaeaea;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .code-tab-title {
            font-weight: 600;
            color: #667eea;
        }
        
        .demo-flow {
            background: #f8f9ff;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 25px;
            margin: 30px 0;
        }
        
        .flow-chart {
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            margin: 20px 0;
        }
        
        .flow-step {
            background: white;
            border: 1px solid #667eea;
            border-radius: 8px;
            padding: 15px 20px;
            margin: 10px;
            min-width: 200px;
            text-align: center;
            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15);
        }
        
        .flow-arrow {
            font-size: 24px;
            color: #667eea;
            margin: 0 10px;
        }
        
        /* 响应式CSS样式优化 */
        @media (max-width: 768px) {
        /* 基础样式调整 */
        body {
        padding-bottom: 30px;
        }
        
        header {
        padding: 60px 0 40px;
        }
        
        h1 {
        font-size: 1.8rem;
        }
        
        h2 {
        font-size: 1.5rem;
        margin: 30px 0 15px;
        }
        
        h3 {
        font-size: 1.2rem;
        margin: 20px 0 10px;
        }
        
        h4 {
        font-size: 1.1rem;
        }
        
        p {
        font-size: 1rem;
        }
        
        .subtitle {
        font-size: 1rem;
        }
        
        .container {
        padding: 0 15px;
        }
        
        .content {
        padding: 80px 15px 20px;
        margin-top: -30px;
        }
        
        /* 移动端目录优化 */
        .toc-mobile-header {
        padding: 12px 15px;
        background-color: #667eea;
        }
        
        .toc-mobile-header h3 {
        color: white;
        font-size: 1.1rem;
        }
        
        .toc-toggle {
        color: white;
        }
        
        .toc-mobile-content {
        top: 52px;
        max-height: 70vh;
        padding: 10px;
        }
        
        .toc {
        background: white;
        border-radius: 0;
        border: none;
        margin: 0;
        padding: 10px 5px;
        }
        
        .toc ul {
        padding: 0;
        }
        
        .toc li {
        margin: 5px 0;
        }
        
        .toc a {
        padding: 8px 10px;
        border-radius: 4px;
        }
        
        .toc a:active {
        background-color: rgba(102, 126, 234, 0.1);
        }
        
        .toc .toc-h3 {
        padding-left: 15px;
        font-size: 0.9rem;
        }
        
        /* 代码块优化 */
        pre {
        padding: 10px;
        margin: 15px -15px;
        border-radius: 0;
        border-left: none;
        border-right: none;
        overflow-x: auto;
        }
        
        .copy-btn {
        padding: 4px 8px;
        font-size: 0.75em;
        right: 5px;
        top: 5px;
        }
        
        /* 流程图和卡片优化 */
        .flow-chart {
        display: block;
        padding: 10px 0;
        }
        
        .flow-step {
        margin: 10px 0;
        min-width: auto;
        width: 100%;
        }
        
        .flow-arrow {
        transform: rotate(90deg);
        margin: 5px 0;
        display: block;
        text-align: center;
        }
        
        .feature-card {
        padding: 20px 15px;
        margin: 15px 0;
        }
        
        .code-tab {
        margin: 15px -15px;
        border-radius: 0;
        border-left: none;
        border-right: none;
        }
        
        /* 提示框优化 */
        .note,
        .warning,
        .success {
        margin: 15px -15px;
        padding: 15px;
        border-radius: 0;
        border-left-width: 4px;
        }
        
        /* 列表优化 */
        ul, ol {
        padding-left: 20px;
        margin: 15px 0;
        }
        
        li {
        margin: 6px 0;
        }
        
        /* 流程图容器优化 */
        .flow-diagram-container {
        margin: 20px -15px;
        overflow-x: auto;
        }
        
        .flow-svg {
        width: 100%;
        min-width: 300px;
        height: auto;
        }
        }
        
        .copy-btn {
            position: absolute;
            top: 10px;
            right: 10px;
            background-color: #667eea;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 5px 10px;
            font-size: 0.8em;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        
        .copy-btn:hover {
            background-color: #5a67d8;
        }
        
        .copy-btn.copied {
            background-color: #4caf50;
        }
        
        .flow-diagram-container {
            margin: 30px 0;
            text-align: center;
        }
        
        /* 流程图样式 */
        .flow-svg {
            width: 100%;
            max-width: 800px;
            height: auto;
            margin: 0 auto;
        }
        
        code {
            font-family: 'Courier New', Courier, monospace;
            background: #f6f8fa;
            padding: 2px 6px;
            border-radius: 3px;
            font-size: 0.9em;
        }
        
        pre code {
            background: none;
            padding: 0;
        }
        
        ul, ol {
            margin: 20px 0;
            padding-left: 30px;
        }
        
        li {
            margin: 8px 0;
        }
        
        .note {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .warning {
            background: #f8d7da;
            border-left: 4px solid #dc3545;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .success {
            background: #d4edda;
            border-left: 4px solid #28a745;
            padding: 15px 20px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        .feature-card {
            background: #f8f9ff;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 25px;
            margin: 20px 0;
            transition: transform 0.3s, box-shadow 0.3s;
        }
        
        .feature-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 8px 30px rgba(0,0,0,0.12);
        }
        
        .code-tab {
            background: #f6f8fa;
            border: 1px solid #e1e4e8;
            border-radius: 6px;
            margin: 20px 0;
            overflow: hidden;
        }
        
        .code-tab-header {
            background-color: #f5f7fa;
            padding: 10px 15px;
            border-bottom: 1px solid #eaeaea;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .code-tab-title {
            font-weight: 600;
            color: #667eea;
        }
        
        .demo-flow {
            background: #f8f9ff;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 25px;
            margin: 30px 0;
        }
        
        .flow-chart {
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            margin: 20px 0;
        }
        
        .flow-step {
            background: white;
            border: 1px solid #667eea;
            border-radius: 8px;
            padding: 15px 20px;
            margin: 10px;
            min-width: 200px;
            text-align: center;
            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15);
        }
        
        .flow-arrow {
            font-size: 24px;
            color: #667eea;
            margin: 0 10px;
        }
        
        @media (max-width: 768px) {
            h1 {
                font-size: 2.2rem;
            }
            
            h2 {
                font-size: 1.8rem;
            }
            
            .content {
                padding: 20px;
            }
            
            .flow-chart {
                flex-direction: column;
            }
            
            .flow-arrow {
                transform: rotate(90deg);
                margin: 10px 0;
            }
        }
    </style>
</head>
<body>
    <header>
        <div class="container">
            <h1>LangGraph 详细介绍与智能客服实现教程</h1>
            <p class="subtitle">探索 LangGraph 框架的强大功能，学习如何构建一个具有多 Agent 协作能力的智能客服系统</p>
        </div>
    </header>
    
    <div class="container">
        <div class="content">
            <!-- 目录 -->
            <div class="toc">
                <h3>目录</h3>
                <ul>
                    <li><a href="#intro">1. LangGraph 介绍</a></li>
                    <li><a href="#concepts">2. 核心概念</a></li>
                    <li><a href="#installation">3. 安装与配置</a></li>
                    <li><a href="#tutorial">4. 详细使用教程</a></li>
                    <li><a href="#smart-customer-service">5. 智能客服实现</a></li>
                    <li><a href="#running-example">6. 运行示例</a></li>
                    <li><a href="#best-practices">7. 最佳实践</a></li>
                </ul>
            </div>
            
            <!-- LangGraph 介绍 -->
            <section id="intro">
                <h2>1. LangGraph 介绍</h2>
                <p>LangGraph 是一个强大的框架，专为构建具有状态管理、循环和条件执行能力的 LLM 应用程序而设计。它基于图（Graph）的概念，允许开发者灵活地编排各种组件，创建复杂的工作流。</p>
                
                <div class="feature-card">
                    <h3>什么是 LangGraph？</h3>
                    <p>LangGraph 是 LangChain 的扩展框架，专注于构建有状态的、多步骤的 LLM 应用。与传统的线性流程不同，LangGraph 允许开发者定义节点（Nodes）和边（Edges），创建更复杂、更灵活的执行路径。</p>
                    <p>LangGraph 的核心优势在于：</p>
                    <ul>
                        <li><strong>状态管理</strong>：轻松管理对话历史、中间结果和上下文信息</li>
                        <li><strong>条件执行</strong>：根据输入或中间结果动态决定执行路径</li>
                        <li><strong>循环支持</strong>：实现需要迭代的复杂任务</li>
                        <li><strong>多 Agent 编排</strong>：轻松协调多个 AI Agent 的工作</li>
                        <li><strong>与 LangChain 无缝集成</strong>：可直接使用 LangChain 的组件生态</li>
                    </ul>
                </div>
            </section>
            
            <!-- 核心概念 -->
            <section id="concepts">
                <h2>2. 核心概念</h2>
                
                <h3>2.1 图（Graph）</h3>
                <p>图是 LangGraph 的核心抽象，它由节点和边组成，定义了应用程序的执行流程。</p>
                
                <h3>2.2 节点（Node）</h3>
                <p>节点代表执行单元，可以是任何函数或操作，例如调用 LLM、执行工具、进行条件判断等。</p>
                
                <h3>2.3 边（Edge）</h3>
                <p>边定义了节点之间的连接关系，决定了执行流程的走向。边可以是静态的，也可以是动态的（根据条件决定）。</p>
                
                <h3>2.4 状态（State）</h3>
                <p>状态是 LangGraph 中的核心概念，它存储了应用程序的上下文信息，可以在不同节点之间传递和修改。</p>
                
                <h3>2.5 Agent</h3>
                <p>Agent 是具有特定功能的智能体，可以是一个 LLM、一个工具集，或者是它们的组合。LangGraph 允许编排多个 Agent 协作完成复杂任务。</p>
                
                <div class="demo-flow">
                    <h4>LangGraph 基本流程图</h4>
                    <div class="flow-chart">
                        <div class="flow-step">输入</div>
                        <span class="flow-arrow">→</span>
                        <div class="flow-step">条件路由</div>
                        <span class="flow-arrow">→</span>
                        <div class="flow-step">Agent 处理</div>
                        <span class="flow-arrow">→</span>
                        <div class="flow-step">状态更新</div>
                        <span class="flow-arrow">→</span>
                        <div class="flow-step">输出</div>
                    </div>
                </div>
            </section>
            
            <!-- 安装与配置 -->
            <section id="installation">
                <h2>3. 安装与配置</h2>
                
                <h3>3.1 安装 LangGraph</h3>
                <p>可以使用 pip 安装 LangGraph：</p>
                <pre><code>pip install langgraph</code></pre>
                
                <div class="note">
                    <p><strong>注意：</strong>如果您需要使用 LangGraph 的高级功能，还需要安装 LangChain 和相应的 LLM 提供商包。</p>
                </div>
                
                <h3>3.2 安装必要的依赖</h3>
                <pre><code>pip install langchain langchain-openai openai</code></pre>
                
                <h3>3.3 环境变量配置</h3>
                <p>为了使用 OpenAI 等服务，您需要配置相应的 API 密钥。您可以在代码中直接设置，也可以通过环境变量配置：</p>
                <pre><code>import os
os.environ["OPENAI_API_KEY"] = "your-api-key-here"</code></pre>
            </section>
            
            <!-- 详细使用教程 -->
            <section id="tutorial">
                <h2>4. 详细使用教程</h2>
                
                <h3>4.1 创建简单的 LangGraph</h3>
                <p>下面是创建一个简单 LangGraph 的基本步骤：</p>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">创建基本的图</span>
                    </div>
                    <pre><code>from langgraph.graph import Graph
from langchain_openai import ChatOpenAI

# 初始化 LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")

# 创建图
graph = Graph()

# 定义节点
def generate_response(state):
    prompt = state["prompt"]
    response = llm.invoke(prompt)
    return {"response": response.content, "prompt": prompt}

# 添加节点
graph.add_node("generate", generate_response)

# 设置入口点
graph.set_entry_point("generate")

# 设置出口点
graph.set_finish_point("generate")

# 编译图
compiled_graph = graph.compile()

# 运行图
result = compiled_graph.invoke({"prompt": "你好，请简单介绍一下 yourself。"})
print(result["response"])</code></pre>
                </div>
                
                <h3>4.2 添加条件路由</h3>
                <p>LangGraph 的一个强大功能是可以根据条件动态决定执行路径：</p>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">添加条件路由</span>
                    </div>
                    <pre><code>from langgraph.graph import Graph
from langchain_openai import ChatOpenAI

# 初始化 LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")

# 创建图
graph = Graph()

# 定义节点
def analyze_query(state):
    query = state["query"]
    # 简单的意图分析
    if "天气" in query:
        return {"intent": "weather", "query": query}
    elif "股票" in query:
        return {"intent": "stock", "query": query}
    else:
        return {"intent": "general", "query": query}

def weather_response(state):
    query = state["query"]
    # 模拟天气查询
    response = f"正在查询天气信息：{query}"
    return {"response": response}

def stock_response(state):
    query = state["query"]
    # 模拟股票查询
    response = f"正在查询股票信息：{query}"
    return {"response": response}

def general_response(state):
    query = state["query"]
    response = llm.invoke(f"回答问题：{query}")
    return {"response": response.content}

# 添加节点
graph.add_node("analyze", analyze_query)
graph.add_node("weather", weather_response)
graph.add_node("stock", stock_response)
graph.add_node("general", general_response)

# 设置路由逻辑
def route_by_intent(state):
    return state["intent"]

# 连接节点
graph.set_entry_point("analyze")
graph.add_conditional_edges("analyze", route_by_intent, {
    "weather": "weather",
    "stock": "stock",
    "general": "general"
})

# 设置出口点
graph.set_finish_point("weather")
graph.set_finish_point("stock")
graph.set_finish_point("general")

# 编译图
compiled_graph = graph.compile()

# 测试
test_queries = [
    {"query": "北京今天的天气怎么样？"},
    {"query": "腾讯的股票价格是多少？"},
    {"query": "什么是人工智能？"}
]

for query in test_queries:
    result = compiled_graph.invoke(query)
    print(f"问题: {query['query']}")
    print(f"回答: {result['response']}")
    print("---")</code></pre>
                </div>
                
                <h3>4.3 状态管理</h3>
                <p>LangGraph 允许您在执行过程中维护和更新状态：</p>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">状态管理示例</span>
                    </div>
                    <pre><code>from langgraph.graph import Graph
from langchain_openai import ChatOpenAI

# 初始化 LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")

# 创建图
graph = Graph()

# 定义节点
def process_message(state):
    # 获取当前消息和历史记录
    new_message = state["message"]
    chat_history = state.get("chat_history", [])
    
    # 更新历史记录
    chat_history.append({"role": "user", "content": new_message})
    
    # 构建完整提示
    full_prompt = "\n".join([f"{msg['role']}: {msg['content']}" for msg in chat_history])
    
    # 调用 LLM
    response = llm.invoke(full_prompt)
    
    # 更新历史记录
    chat_history.append({"role": "assistant", "content": response.content})
    
    return {
        "response": response.content,
        "chat_history": chat_history
    }

# 添加节点
graph.add_node("process", process_message)

# 设置入口点和出口点
graph.set_entry_point("process")
graph.set_finish_point("process")

# 编译图
compiled_graph = graph.compile()

# 开始对话
state = {"message": "你好，我是小明。", "chat_history": []}
result = compiled_graph.invoke(state)
print(f"助手: {result['response']}")

# 继续对话
state = {"message": "你还记得我是谁吗？", "chat_history": result['chat_history']}
result = compiled_graph.invoke(state)
print(f"助手: {result['response']}")</code></pre>
                </div>
                
                <h3>4.4 循环执行</h3>
                <p>LangGraph 支持循环执行，可以实现需要多次迭代的任务：</p>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">循环执行示例</span>
                    </div>
                    <pre><code>from langgraph.graph import Graph
from langchain_openai import ChatOpenAI

# 初始化 LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")

# 创建图
graph = Graph()

# 定义节点
def generate_ideas(state):
    topic = state["topic"]
    iteration = state.get("iteration", 0)
    ideas = state.get("ideas", [])
    
    # 生成新想法
    prompt = f"为主题 '{topic}' 生成第 {iteration + 1} 个创意想法"
    response = llm.invoke(prompt)
    
    # 添加到想法列表
    ideas.append(response.content)
    
    return {
        "ideas": ideas,
        "iteration": iteration + 1,
        "topic": topic
    }

def check_iterations(state):
    # 检查是否达到最大迭代次数
    max_iterations = 3  # 生成3个想法
    if state["iteration"] < max_iterations:
        return "continue"
    else:
        return "finish"

# 添加节点
graph.add_node("generate", generate_ideas)
graph.add_node("check", check_iterations)

# 连接节点
graph.set_entry_point("generate")
graph.add_edge("generate", "check")
graph.add_conditional_edges(
    "check",
    lambda x: x,
    {
        "continue": "generate",
        "finish": "generate"
    }
)

# 设置出口点
graph.set_finish_point("generate")

# 编译图
compiled_graph = graph.compile()

# 运行图
result = compiled_graph.invoke({"topic": "可持续发展"})

# 输出结果
print(f"主题: {result['topic']}")
print("生成的想法:")
for i, idea in enumerate(result['ideas'], 1):
    print(f"{i}. {idea}")</code></pre>
                </div>
            </section>
            
            <!-- 智能客服实现 -->
            <section id="smart-customer-service">
                <h2>5. 智能客服实现</h2>
                
                <p>在本节中，我们将设计并实现一个基于 LangGraph 的智能客服系统，该系统具备三种核心能力：订单处理、京东电商产品介绍和 IT 技术回答。我们将创建三个专门的 Agent，并使用 LangGraph 将它们编排起来，实现根据用户问题自动选择合适的 Agent 进行回答。</p>
                
                <h3>5.1 系统架构设计</h3>
                
                <div class="flow-diagram-container">
                    <h4>智能客服系统架构</h4>
                    <svg class="flow-svg" viewBox="0 0 800 150" xmlns="http://www.w3.org/2000/svg">
                        <!-- 流程节点 -->
                        <rect x="50" y="50" width="120" height="50" rx="8" fill="#667eea" />
                        <rect x="210" y="50" width="120" height="50" rx="8" fill="#667eea" />
                        <rect x="370" y="50" width="120" height="50" rx="8" fill="#667eea" />
                        <rect x="530" y="50" width="120" height="50" rx="8" fill="#667eea" />
                        <rect x="690" y="50" width="120" height="50" rx="8" fill="#667eea" />
                        
                        <!-- 节点文字 -->
                        <text x="110" y="75" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle">用户输入</text>
                        <text x="270" y="75" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle">意图识别</text>
                        <text x="430" y="75" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle">条件路由</text>
                        <text x="590" y="75" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle">对应Agent</text>
                        <text x="750" y="75" font-size="16" fill="white" text-anchor="middle" dominant-baseline="middle">回答生成</text>
                        
                        <!-- 连接线 -->
                        <line x1="170" y1="75" x2="210" y2="75" stroke="#667eea" stroke-width="3" />
                        <line x1="330" y1="75" x2="370" y2="75" stroke="#667eea" stroke-width="3" />
                        <line x1="490" y1="75" x2="530" y2="75" stroke="#667eea" stroke-width="3" />
                        <line x1="650" y1="75" x2="690" y2="75" stroke="#667eea" stroke-width="3" />
                        
                        <!-- 箭头 -->
                        <polygon points="170,70 210,75 170,80" fill="#667eea" />
                        <polygon points="330,70 370,75 330,80" fill="#667eea" />
                        <polygon points="490,70 530,75 490,80" fill="#667eea" />
                        <polygon points="650,70 690,75 650,80" fill="#667eea" />
                    </svg>
                </div>
                
                <h3>5.2 三个 Agent 的设计</h3>
                
                <div class="feature-card">
                    <h4>1. 订单处理 Agent</h4>
                    <p><strong>功能：</strong>处理用户的订单相关查询，包括订单状态查询、修改订单、取消订单等。</p>
                    <p><strong>实现方式：</strong>使用 LLM 理解用户需求，结合模拟的订单数据库进行操作。</p>
                </div>
                
                <div class="feature-card">
                    <h4>2. 京东电商产品介绍 Agent</h4>
                    <p><strong>功能：</strong>为用户提供京东电商平台上的产品信息，包括产品介绍、价格查询、促销活动等。</p>
                    <p><strong>实现方式：</strong>使用 LLM 理解用户需求，结合模拟的产品数据库进行查询。</p>
                </div>
                
                <div class="feature-card">
                    <h4>3. IT 技术回答 Agent</h4>
                    <p><strong>功能：</strong>回答用户关于 IT 技术方面的问题，包括编程、网络、硬件等。</p>
                    <p><strong>实现方式：</strong>使用 LLM 的知识直接回答用户问题。</p>
                </div>
                
                <h3>5.3 完整实现代码</h3>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">智能客服主程序 (smart_customer_service.py)</span>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>import os
from langgraph.graph import Graph
from langchain_openai import ChatOpenAI
import json

# 设置环境变量
os.environ["OPENAI_API_KEY"] = "your-api-key-here"

# 初始化 LLM
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)

# 模拟数据 - 订单数据库
ORDER_DATABASE = {
    "ORD123456": {"status": "已发货", "product": "iPhone 15", "quantity": 1, "price": 5999},
    "ORD654321": {"status": "待付款", "product": "AirPods Pro", "quantity": 1, "price": 1899},
    "ORD789012": {"status": "已完成", "product": "MacBook Pro", "quantity": 1, "price": 12999}
}

# 模拟数据 - 产品数据库
PRODUCT_DATABASE = {
    "iPhone 15": {"description": "苹果最新款手机，搭载A17 Pro芯片", "price": 5999, "stock": 100},
    "MacBook Pro": {"description": "专业级笔记本电脑，M3 Max芯片", "price": 12999, "stock": 50},
    "AirPods Pro": {"description": "主动降噪无线耳机", "price": 1899, "stock": 200},
    "iPad Pro": {"description": "专业级平板电脑", "price": 6299, "stock": 80}
}

# 1. 意图识别节点
def intent_recognition(state):
    """识别用户意图，确定应该路由到哪个Agent"""
    query = state["query"]
    
    # 使用LLM进行意图分类
    prompt = f"""
    请将用户的问题分类为以下三个类别之一：
    1. order - 与订单相关的问题，包括订单查询、修改、取消等
    2. product - 与产品相关的问题，包括产品介绍、价格、促销等
    3. tech - 与IT技术相关的问题
    
    只返回类别名称，不要返回其他内容。
    
    用户问题：{query}
    """
    
    response = llm.invoke(prompt)
    intent = response.content.strip().lower()
    
    # 简单的关键词后备方案
    if intent not in ["order", "product", "tech"]:
        if any(keyword in query for keyword in ["订单", "ORD", "订单号", "发货", "付款", "取消"]):
            intent = "order"
        elif any(keyword in query for keyword in ["产品", "价格", "促销", "库存", "型号", "规格"]):
            intent = "product"
        else:
            intent = "tech"
    
    print(f"意图识别结果: {intent}")
    return {"query": query, "intent": intent}

# 2. 订单处理 Agent
def order_agent(state):
    """处理订单相关查询"""
    query = state["query"]
    
    # 提取订单号 (简单实现)
    order_id = None
    for key in ORDER_DATABASE.keys():
        if key in query:
            order_id = key
            break
    
    if order_id:
        # 查询订单
        if order_id in ORDER_DATABASE:
            order_info = ORDER_DATABASE[order_id]
            response = f"您的订单 {order_id} 信息如下：\n"
            response += f"状态：{order_info['status']}\n"
            response += f"商品：{order_info['product']}\n"
            response += f"数量：{order_info['quantity']}\n"
            response += f"总价：¥{order_info['price']}"
        else:
            response = f"抱歉，未找到订单号为 {order_id} 的订单"
    else:
        # 通用订单问题
        prompt = f"""
        请以订单客服的身份回答用户问题：{query}
        
        我们的订单服务包括：
        - 订单状态查询
        - 订单修改
        - 订单取消
        - 退款申请
        - 物流查询
        
        如果用户询问具体订单，请要求用户提供订单号。
        """
        response_llm = llm.invoke(prompt)
        response = response_llm.content
    
    return {"response": response, "agent": "order_agent"}

# 3. 产品介绍 Agent
def product_agent(state):
    """处理产品相关查询"""
    query = state["query"]
    
    # 查找产品 (简单实现)
    product_name = None
    for key in PRODUCT_DATABASE.keys():
        if key in query:
            product_name = key
            break
    
    if product_name:
        # 查询产品信息
        if product_name in PRODUCT_DATABASE:
            product_info = PRODUCT_DATABASE[product_name]
            response = f"{product_name} 产品信息：\n"
            response += f"描述：{product_info['description']}\n"
            response += f"价格：¥{product_info['price']}\n"
            response += f"库存：{product_info['stock']} 件"
        else:
            response = f"抱歉，我们暂时没有 {product_name} 的信息"
    else:
        # 通用产品问题
        prompt = f"""
        请以京东电商客服的身份回答用户问题：{query}
        
        我们提供以下产品类型：
        - 手机 (如iPhone, 华为等)
        - 电脑 (如MacBook, 联想等)
        - 耳机 (如AirPods, Sony等)
        - 平板电脑 (如iPad, 华为平板等)
        
        请提供专业、友好的产品介绍和建议。
        """
        response_llm = llm.invoke(prompt)
        response = response_llm.content
    
    return {"response": response, "agent": "product_agent"}

# 4. IT技术回答 Agent
def tech_agent(state):
    """回答IT技术相关问题"""
    query = state["query"]
    
    prompt = f"""
    请以IT技术专家的身份回答用户问题：{query}
    
    请提供准确、详细且专业的技术解答，包括：
    - 问题的技术原理
    - 具体的解决方案
    - 如果适用，提供代码示例
    - 相关的最佳实践建议
    
    回答应当友好且易于理解，同时保持专业性。
    """
    
    response_llm = llm.invoke(prompt)
    response = response_llm.content
    
    return {"response": response, "agent": "tech_agent"}

# 5. 创建并配置图
def create_customer_service_graph():
    """创建智能客服的LangGraph"""
    # 创建图
    graph = Graph()
    
    # 添加节点
    graph.add_node("intent_recognition", intent_recognition)
    graph.add_node("order_agent", order_agent)
    graph.add_node("product_agent", product_agent)
    graph.add_node("tech_agent", tech_agent)
    
    # 设置入口点
    graph.set_entry_point("intent_recognition")
    
    # 添加条件边，根据意图路由到不同的Agent
    graph.add_conditional_edges(
        "intent_recognition",
        lambda state: state["intent"],
        {
            "order": "order_agent",
            "product": "product_agent",
            "tech": "tech_agent"
        }
    )
    
    # 设置出口点
    graph.set_finish_point("order_agent")
    graph.set_finish_point("product_agent")
    graph.set_finish_point("tech_agent")
    
    # 编译图
    return graph.compile()

# 6. 主函数
def main():
    """运行智能客服系统"""
    # 创建图
    app = create_customer_service_graph()
    
    print("欢迎使用智能客服系统！请输入您的问题，输入'退出'结束对话。")
    
    while True:
        # 获取用户输入
        user_query = input("\n您: ")
        
        if user_query.lower() in ["退出", "exit", "quit"]:
            print("感谢使用，再见！")
            break
        
        # 运行图
        result = app.invoke({"query": user_query})
        
        # 显示回答
        print(f"\n客服: {result['response']}")
        print(f"(由 {result['agent']} 处理)")

if __name__ == "__main__":
    main()</code></pre>
                </div>
                
                <h3>5.4 系统工作流程说明</h3>
                
                <ol>
                    <li><strong>意图识别</strong>：系统首先使用 LLM 对用户输入进行意图分类，判断是订单类、产品类还是技术类问题。</li>
                    <li><strong>条件路由</strong>：根据识别出的意图，LangGraph 将请求路由到相应的专用 Agent。</li>
                    <li><strong>Agent 处理</strong>：专用 Agent 根据自身职责处理用户请求，生成回答。</li>
                    <li><strong>回答返回</strong>：系统将 Agent 生成的回答返回给用户，并显示由哪个 Agent 处理的信息。</li>
                </ol>
                
                <div class="note">
                    <p><strong>注意：</strong>在实际应用中，您可以扩展这个系统，例如添加更多的 Agent、改进意图识别算法、接入真实的数据库和 API 等。</p>
                </div>
            </section>
            
            <!-- 运行示例 -->
            <section id="running-example">
                <h2>6. 运行示例</h2>
                
                <h3>6.1 准备工作</h3>
                
                <ol>
                    <li><strong>安装必要的依赖</strong>：
                        <pre><code>pip install langgraph langchain langchain-openai openai</code></pre>
                    </li>
                    <li><strong>准备 API 密钥</strong>：您需要一个 OpenAI API 密钥来运行此示例。</li>
                    <li><strong>创建代码文件</strong>：将上面的智能客服代码保存为 <code>smart_customer_service.py</code>。</li>
                </ol>
                
                <h3>6.2 配置步骤</h3>
                
                <div class="warning">
                    <p><strong>重要：</strong>请确保替换代码中的 <code>your-api-key-here</code> 为您自己的 OpenAI API 密钥。</p>
                </div>
                
                <pre><code># 在 smart_customer_service.py 文件中修改以下行
os.environ["OPENAI_API_KEY"] = "your-api-key-here"  # 替换为您的实际 API 密钥</code></pre>
                
                <h3>6.3 运行步骤</h3>
                
                <ol>
                    <li><strong>打开终端</strong>，导航到保存代码的目录。</li>
                    <li><strong>运行命令</strong>：
                        <pre><code>python smart_customer_service.py</code></pre>
                    </li>
                    <li><strong>与智能客服对话</strong>：系统启动后，您可以输入问题进行交互。</li>
                </ol>
                
                <h3>6.4 实际运行示例</h3>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">订单查询示例</span>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>欢迎使用智能客服系统！请输入您的问题，输入'退出'结束对话。

您: 我的订单ORD123456的状态是什么？
意图识别结果: order

客服: 您的订单 ORD123456 信息如下：
状态：已发货
商品：iPhone 15
数量：1
总价：¥5999
(由 order_agent 处理)</code></pre>
                </div>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">产品查询示例</span>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>您: iPhone 15 的价格是多少？
意图识别结果: product

客服: iPhone 15 产品信息：
描述：苹果最新款手机，搭载A17 Pro芯片
价格：¥5999
库存：100 件
(由 product_agent 处理)</code></pre>
                </div>
                
                <div class="code-tab">
                    <div class="code-tab-header">
                        <span class="code-tab-title">技术问题示例</span>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>您: 什么是Python中的装饰器？如何使用？
意图识别结果: tech

客服: Python中的装饰器是一种特殊类型的函数，它可以修改其他函数的行为而无需直接更改其源代码。装饰器本质上是一个高阶函数，它接受一个函数作为输入并返回另一个函数。

基本语法：
```python
@decorator
def function():
    # 函数体
```

这等价于：
```python
def function():
    # 函数体
function = decorator(function)
```

简单示例：
```python
def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数 {func.__name__} 执行时间: {end - start} 秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "完成"

result = slow_function()  # 输出: 函数 slow_function 执行时间: 1.000... 秒
```

装饰器可以用于：
- 日志记录
- 性能监控
- 权限验证
- 缓存
- 输入验证等场景
(由 tech_agent 处理)</code></pre>
                </div>
                
                <h3>6.5 可能遇到的问题与解决方案</h3>
                
                <div class="feature-card">
                    <h4>API 密钥错误</h4>
                    <p><strong>问题：</strong>运行时出现 API 密钥无效的错误。</p>
                    <p><strong>解决方案：</strong>确保您的 OpenAI API 密钥有效且已正确设置。</p>
                </div>
                
                <div class="feature-card">
                    <h4>依赖安装失败</h4>
                    <p><strong>问题：</strong>无法安装某些 Python 包。</p>
                    <p><strong>解决方案：</strong>尝试升级 pip，然后重新安装：
                        <pre><code>pip install --upgrade pip
pip install langgraph langchain langchain-openai openai</code></pre>
                    </p>
                </div>
                
                <div class="feature-card">
                    <h4>意图识别不准确</h4>
                    <p><strong>问题：</strong>系统经常将问题路由到错误的 Agent。</p>
                    <p><strong>解决方案：</strong>改进 <code>intent_recognition</code> 函数中的提示词，或者增强关键词匹配逻辑。</p>
                </div>
            </section>
            
            <!-- 最佳实践 -->
            <section id="best-practices">
                <h2>7. 最佳实践</h2>
                
                <h3>7.1 LangGraph 使用最佳实践</h3>
                
                <ol>
                    <li><strong>节点设计原则</strong>
                        <ul>
                            <li>每个节点应职责单一，专注于完成一个特定任务</li>
                            <li>节点之间通过状态传递数据，保持松耦合</li>
                            <li>为复杂节点添加适当的错误处理逻辑</li>
                        </ul>
                    </li>
                    <li><strong>状态管理技巧</strong>
                        <ul>
                            <li>状态设计应简洁明了，只包含必要的数据</li>
                            <li>使用标准化的数据结构存储和传递信息</li>
                            <li>定期清理不再需要的状态数据，避免内存泄漏</li>
                        </ul>
                    </li>
                    <li><strong>性能优化建议</strong>
                        <ul>
                            <li>合理缓存中间结果，避免重复计算</li>
                            <li>对于计算密集型任务，考虑异步执行</li>
                            <li>优化 LLM 调用，使用适当的提示词和参数</li>
                        </ul>
                    </li>
                </ol>
                
                <h3>7.2 智能客服系统最佳实践</h3>
                
                <ol>
                    <li><strong>意图识别优化</strong>
                        <ul>
                            <li>使用更高级的 NLP 技术提高意图识别准确率</li>
                            <li>收集真实用户数据，持续优化识别模型</li>
                            <li>考虑使用专门的意图识别服务或模型</li>
                        </ul>
                    </li>
                    <li><strong>Agent 设计原则</strong>
                        <ul>
                            <li>为每个 Agent 明确定义职责边界</li>
                            <li>设计统一的输出格式，确保用户体验一致性</li>
                            <li>为 Agent 添加自我纠正和错误处理能力</li>
                        </ul>
                    </li>
                    <li><strong>系统扩展建议</strong>
                        <ul>
                            <li>设计可插拔的 Agent 架构，方便添加新功能</li>
                            <li>实现 Agent 之间的协作机制，处理复杂问题</li>
                            <li>考虑添加人工干预通道，处理系统无法解决的问题</li>
                        </ul>
                    </li>
                </ol>
                
                <div class="success">
                    <h4>总结</h4>
                    <p>通过本教程，您学习了如何使用 LangGraph 构建一个具有多 Agent 协作能力的智能客服系统。LangGraph 提供了强大的状态管理和条件执行能力，使您能够构建复杂的工作流程。希望本教程对您有所帮助！</p>
                </div>
            </section>
        </div>
    </div>
<script>
        // 代码复制功能
        function copyCode(button) {
            const codeBlock = button.closest('.code-tab') ? button.closest('.code-tab').querySelector('pre code') : button.closest('pre').querySelector('code');
            const textToCopy = codeBlock.textContent;
            
            navigator.clipboard.writeText(textToCopy).then(function() {
                button.textContent = '已复制!';
                button.classList.add('copied');
                
                setTimeout(function() {
                    button.textContent = '复制代码';
                    button.classList.remove('copied');
                }, 2000);
            }).catch(function(err) {
                console.error('复制失败:', err);
            });
        }
        
        // 目录折叠/展开功能
        function setupTocToggle(toggleId, contentId, isMobile) {
            if (isMobile === undefined) {
                isMobile = false;
            }
            const toggle = document.getElementById(toggleId);
            const content = document.getElementById(contentId);
            
            if (!toggle || !content) return;
            
            // 保存初始状态
            const initialState = {
                toggleClass: toggle.className,
                contentClass: content.className
            };
            
            toggle.addEventListener('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
                
                // 切换折叠状态
                if (isMobile) {
                    this.classList.toggle('collapsed');
                    content.classList.toggle('open');
                } else {
                    this.classList.toggle('collapsed');
                    content.classList.toggle('collapsed');
                }
                
                // 保存用户的折叠偏好到localStorage
                const isCollapsed = isMobile ? !content.classList.contains('open') : content.classList.contains('collapsed');
                localStorage.setItem('toc_' + toggleId + '_collapsed', isCollapsed.toString());
            });
            
            // 从localStorage恢复用户偏好的折叠状态
            const savedState = localStorage.getItem('toc_' + toggleId + '_collapsed');
            if (savedState !== null) {
                const shouldCollapse = savedState === 'true';
                if (shouldCollapse) {
                    toggle.classList.add('collapsed');
                    if (isMobile) {
                        content.classList.remove('open');
                    } else {
                        content.classList.add('collapsed');
                    }
                }
            }
        }
        
        // 设置导航链接功能
        function setupNavLinks() {
            const navLinks = document.querySelectorAll('.nav-link');
            
            for (let i = 0; i < navLinks.length; i++) {
                const link = navLinks[i];
                link.addEventListener('click', function(e) {
                    e.preventDefault();
                    
                    // 获取目标ID
                    const targetId = this.getAttribute('href');
                    const targetElement = document.querySelector(targetId);
                    
                    if (targetElement) {
                        // 移除所有活动状态
                        for (let j = 0; j < navLinks.length; j++) {
                            navLinks[j].classList.remove('active');
                        }
                        
                        // 添加当前活动状态
                        this.classList.add('active');
                        
                        // 滚动到目标位置
                        const headerOffset = 60; // 考虑固定头部的高度
                        const elementPosition = targetElement.getBoundingClientRect().top;
                        const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
                        
                        window.scrollTo({
                            top: offsetPosition,
                            behavior: 'smooth'
                        });
                        
                        // 关闭移动端目录
                        const mobileTocContent = document.getElementById('mobileTocContent');
                        const mobileTocToggle = document.getElementById('mobileTocToggle');
                        if (mobileTocContent && mobileTocToggle) {
                            mobileTocContent.classList.remove('open');
                            mobileTocToggle.classList.remove('collapsed');
                        }
                        
                        // 保存最后访问的章节
                        localStorage.setItem('last_visited_section', targetId);
                    }
                });
            }
        }
        
        // 监听滚动，更新活动导航项
        function setupScrollSpy() {
            // 为了性能优化，使用节流函数
            function throttle(func, delay) {
                let timeoutId;
                return function() {
                    const context = this;
                    const args = arguments;
                    if (!timeoutId) {
                        timeoutId = setTimeout(function() {
                            func.apply(context, args);
                            timeoutId = null;
                        }, delay);
                    }
                };
            }
            
            function updateActiveSection() {
                const sections = document.querySelectorAll('section[id]');
                let currentSection = '';
                const scrollPosition = window.scrollY + 100; // 添加偏移量
                
                // 从下往上查找，找到第一个在视口中的章节
                for (let i = sections.length - 1; i >= 0; i--) {
                    const section = sections[i];
                    const sectionTop = section.offsetTop;
                    
                    if (scrollPosition >= sectionTop) {
                        currentSection = '#' + section.getAttribute('id');
                        break;
                    }
                }
                
                // 更新导航链接的活动状态
                const navLinks = document.querySelectorAll('.nav-link');
                for (let i = 0; i < navLinks.length; i++) {
                    const link = navLinks[i];
                    link.classList.remove('active');
                    if (link.getAttribute('href') === currentSection) {
                        link.classList.add('active');
                        
                        // 确保活动链接在可见区域内（适用于长目录）
                        const container = link.closest('.toc-content');
                        if (container) {
                            const linkRect = link.getBoundingClientRect();
                            const containerRect = container.getBoundingClientRect();
                            
                            if (linkRect.top < containerRect.top || linkRect.bottom > containerRect.bottom) {
                                link.scrollIntoView({ behavior: 'smooth', block: 'center' });
                            }
                        }
                    }
                }
            }
            
            // 使用节流函数监听滚动事件
            window.addEventListener('scroll', throttle(updateActiveSection, 200));
            
            // 初始加载时更新活动章节
            updateActiveSection();
            
            // 尝试从localStorage恢复上次访问的章节
            const lastSection = localStorage.getItem('last_visited_section');
            if (lastSection) {
                const lastElement = document.querySelector(lastSection);
                if (lastElement && window.location.hash === '') { // 只有在没有URL hash时才恢复
                    setTimeout(function() {
                        const headerOffset = 60;
                        const elementPosition = lastElement.getBoundingClientRect().top;
                        const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
                        
                        window.scrollTo({
                            top: offsetPosition,
                            behavior: 'smooth'
                        });
                    }, 500);
                }
            }
        }
        
        // 为所有代码块添加复制按钮
        function addCopyButtons() {
            const codeBlocks = document.querySelectorAll('pre');
            for (let i = 0; i < codeBlocks.length; i++) {
                const block = codeBlocks[i];
                // 如果已经有复制按钮，跳过
                if (block.querySelector('.copy-btn')) continue;
                
                const copyButton = document.createElement('button');
                copyButton.className = 'copy-btn';
                copyButton.textContent = '复制代码';
                copyButton.onclick = function() {
                    copyCode(this);
                };
                
                block.style.position = 'relative';
                block.appendChild(copyButton);
            }
        }
        
        // 移动端触摸优化
        function setupMobileOptimizations() {
            // 阻止移动端的默认触摸行为，提高滚动体验
            const contentArea = document.querySelector('.content');
            if (contentArea) {
                contentArea.addEventListener('touchmove', function(e) {
                    // 只有当目录打开时，阻止内容区域的滚动
                    const mobileTocContent = document.getElementById('mobileTocContent');
                    if (mobileTocContent && mobileTocContent.classList.contains('open')) {
                        e.preventDefault();
                    }
                }, { passive: false });
            }
            
            // 点击页面其他区域关闭移动端目录
            document.addEventListener('click', function(e) {
                const mobileTocHeader = document.querySelector('.toc-mobile-header');
                const mobileTocContent = document.getElementById('mobileTocContent');
                
                if (mobileTocHeader && mobileTocContent && 
                    !mobileTocHeader.contains(e.target) && 
                    !mobileTocContent.contains(e.target) && 
                    mobileTocContent.classList.contains('open')) {
                    mobileTocContent.classList.remove('open');
                    const mobileTocToggle = document.getElementById('mobileTocToggle');
                    if (mobileTocToggle) {
                        mobileTocToggle.classList.remove('collapsed');
                    }
                }
            });
        }
        
        // 页面加载完成后初始化所有功能
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化桌面端目录折叠功能
            setupTocToggle('desktopTocToggle', 'desktopTocContent', false);
            
            // 初始化移动端目录折叠功能
            setupTocToggle('mobileTocToggle', 'mobileTocContent', true);
            
            // 初始化导航链接
            setupNavLinks();
            
            // 设置滚动监听
            setupScrollSpy();
            
            // 添加复制按钮
            addCopyButtons();
            
            // 移动端优化
            setupMobileOptimizations();
            
            console.log('LangGraph 文档交互功能已初始化');
        });
        </script>
        <style>
        /* 目录样式优化 */
        .toc-toggle {
            transition: all 0.3s ease;
            cursor: pointer;
            user-select: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 10px 15px;
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 6px;
            margin-bottom: 10px;
            font-weight: 600;
            color: #333;
        }

        .toc-toggle:hover {
            background-color: #e9ecef;
            transform: translateY(-1px);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }

        .toc-toggle.collapsed {
            background-color: #f1f3f5;
        }

        .toc-toggle::after {
            content: '▼';
            font-size: 0.8em;
            transition: transform 0.3s ease;
            display: inline-block;
            width: 16px;
            text-align: center;
        }

        .toc-toggle.collapsed::after {
            transform: rotate(-90deg);
        }

        /* 桌面端目录优化 */
        .toc-desktop {
            position: sticky;
            top: 20px;
            max-height: calc(100vh - 40px);
            overflow: hidden;
            transition: max-height 0.3s ease;
        }

        .toc-desktop .toc-content {
            overflow-y: auto;
            max-height: calc(100vh - 100px);
            padding-right: 5px;
            transition: all 0.3s ease;
            scrollbar-width: thin;
            scrollbar-color: #ccc transparent;
        }

        .toc-desktop .toc-content.collapsed {
            max-height: 0;
            opacity: 0;
            padding-right: 0;
        }

        /* 移动端目录优化 */
        .toc-mobile-header {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1000;
            background-color: #fff;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            padding: 10px 15px;
            transition: background-color 0.3s ease;
        }

        .toc-mobile .toc-content {
            position: fixed;
            top: 50px;
            left: 0;
            right: 0;
            background-color: #fff;
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease, box-shadow 0.3s ease;
            z-index: 999;
        }

        .toc-mobile .toc-content.open {
            max-height: calc(100vh - 50px);
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        /* 导航链接样式优化 */
        .nav-list {
            list-style: none;
            padding-left: 0;
            margin: 0;
        }

        .nav-item {
            margin: 2px 0;
        }

        .nav-link {
            display: block;
            padding: 8px 12px;
            color: #495057;
            text-decoration: none;
            border-radius: 4px;
            transition: all 0.2s ease;
            border-left: 3px solid transparent;
        }

        .nav-link:hover {
            background-color: #f8f9fa;
            color: #007bff;
            transform: translateX(3px);
        }

        .nav-link.active {
            background-color: #e3f2fd;
            color: #0056b3;
            border-left-color: #007bff;
            font-weight: 600;
        }

        /* 子导航样式 */
        .nav-list .nav-list {
            padding-left: 20px;
            margin-top: 4px;
        }

        .nav-list .nav-list .nav-link {
            font-size: 0.95em;
            padding: 6px 8px;
        }

        /* 响应式优化 */
        @media (max-width: 768px) {
            .toc-toggle {
                padding: 12px 15px;
                font-size: 16px;
            }

            .nav-link {
                padding: 12px 15px;
                font-size: 16px;
            }

            .nav-list .nav-list .nav-link {
                padding: 10px 8px 10px 15px;
            }

            .content {
                margin-top: 70px;
            }
        }

        /* 高对比度和无障碍支持 */
        @media (prefers-reduced-motion: reduce) {
            * {
                transition: none !important;
                animation: none !important;
            }
        }

        /* 滚动条美化 */
        .toc-content::-webkit-scrollbar {
            width: 6px;
        }

        .toc-content::-webkit-scrollbar-track {
            background: transparent;
        }

        .toc-content::-webkit-scrollbar-thumb {
            background-color: #ccc;
            border-radius: 3px;
        }

        .toc-content::-webkit-scrollbar-thumb:hover {
            background-color: #aaa;
        }

        /* 目录动画效果 */
        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        .toc-content {
            animation: fadeIn 0.3s ease-out;
        }
    </style>
</body>
</html>